﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using BattleNet.DataAccess.Parsers.Exceptions;
using BattleNet.DataAccess.Parsers.Interface;
using BattleNet.DataAccess.SourceProviders.Interface;
using BattleNet.Entities;
using BattleNet.Entities.Enums;
using HtmlAgilityPack;
using BattleNet.DataAccess.Extensions;

namespace BattleNet.DataAccess.Parsers.Html
{
    public class HtmlRealmFinder : IRealmFinder
    {
        private HtmlDocument _doc;

        
        public HtmlRealmFinder(ISourceProvider<string> source)
        {
            if(source == null)
            {
                throw new ArgumentNullException("source");
            }

            _doc = new HtmlDocument();
            _doc.LoadHtml(source.Provide());
        }

        public Realm Find(string realmName)
        {
            if(String.IsNullOrWhiteSpace(realmName))
            {
                throw new ArgumentNullException("realmName");
            }

            HtmlNode realmRow = GetRealmTr(_doc, realmName);
            List<HtmlNode> realmProperties = realmRow.Elements("td").ToList();
           
            try
            {
                return CreateRealm(realmProperties);
            }
            catch(Exception ex)
            {
               throw new HtmlParsingException(ex);               
            }
        }

        private Realm CreateRealm(List<HtmlNode> realmProperties)
        {
            string locale =
                realmProperties.FirstOrDefault(x => x.HasClass("locale")).InnerText.Trim();
            string name = 
                realmProperties.FirstOrDefault(x => x.HasClass("name")).InnerText.Trim();
            PopulationStatus population =
                realmProperties.FirstOrDefault(x => x.HasClass("population")).GetAttributeValue("data-raw").ToEnum<PopulationStatus>();
            bool queue =
                Convert.ToBoolean(realmProperties.FirstOrDefault(x => x.HasClass("queue")).GetAttributeValue("data-raw"));
            RealmType type = 
                realmProperties.FirstOrDefault(x => x.HasClass("type")).GetAttributeValue("data-raw").ToEnum<RealmType>();
            RealmStatus status =
                realmProperties.FirstOrDefault(x => x.HasClass("status")).GetAttributeValue("data-raw").ToEnum<RealmStatus>();

            return new Realm
                       {
                           Locale = WebUtility.HtmlDecode(locale),
                           Name = WebUtility.HtmlDecode(name),
                           Population = population,
                           Queue = queue,
                           Status = status,
                           Type = type
                       };
        }

        private HtmlNode GetRealmTr(HtmlDocument doc, string realmName)
        {
            HtmlNodeCollection rows = GetAllRealmRows(doc);
            return GetRealmFromRows(rows, realmName);
        }

        private HtmlNodeCollection GetAllRealmRows(HtmlDocument doc)
        {
            HtmlNodeCollection rows = doc.DocumentNode.SelectNodes("//div[@id='all-realms']/div/table/tbody//tr");

            if (rows == null)
            {
                throw new HtmlParsingException();
            }

            return rows;
        }

        private HtmlNode GetRealmFromRows(HtmlNodeCollection rows, string realmName)
        {

            var realmRow =
                rows.Where(x => x.Elements("td").Any(column => column.HasClass("name") &&
                                                               column.InnerText.Trim() == realmName)).FirstOrDefault();
            if (realmRow == null)
            {
                throw new RealmNotFoundException();
            }

            return realmRow;
        }

        
    }
}